// Copyright 2008 web2me.dev
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.

package net.web2me.api.util;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.Authenticator;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;

import org.apache.log4j.Logger;

/**
 * Generates stream from a site
 * @author web2me
 */
public class SiteStreamGenerator {
	
	private static Logger logger = Logger.getLogger(SiteStreamGenerator.class);
	private static int retryOnTimeOut = 20;
	
	/**
	 * Generates stream from the given URL, setting previously the cookies.<br>
	 * The cookies parameters should look like the following:<br>
	 * <pre>
	 * key1=value1;key2=value2
	 * </pre>
	 * @param url The URL to get the stream
	 * @param cookies A semicolon separated key-value cookies
	 * @return A string with the URL content
	 * @throws UtilityException
	 */
	public static String getStream(String url, String cookies) throws UtilityException{
		URL urlSite = null;
		try {
			urlSite = new URL(url);
		} catch (MalformedURLException e) {
			throw new UtilityException(e);
		}
		
		try {
			URLConnection conn = urlSite.openConnection();
			
			if(cookies != null){
				conn.setRequestProperty("Cookie", cookies);
			}
			
			conn.setConnectTimeout(0);
		} catch (IOException e2) {
			logger.error("IOException caught", e2);
			throw new UtilityException(e2);
		}
		
		String finalStream = null;
		
		logger.info("Loading site stream for \"" + url + "\"");
		try{
			finalStream = getStringFromStream(urlSite.openStream());
		}catch(Exception e){
			if(e.getMessage().indexOf("Server returned HTTP response code: 401") > -1){
				try {
					finalStream = getStreamWithAuthentication(url);
				} catch (MalformedURLException e1) {
					logger.error("MalformedURLException caught", e1);
					throw new UtilityException(e1);
				} catch (IOException e3) {
					logger.error("IOException caught", e);
					throw new UtilityException(e3);
				}
			}else{
				if( retryOnTimeOut > 0 ){
					logger.warn("Timeout detected. Retrying...");
					retryOnTimeOut--;
					
					finalStream = getStream(url);
				}else{
					throw new UtilityException(e);
				}	
			}
		}
		
		if(finalStream == null){
			throw new UtilityException("The stream couldn't be loaded");
		}
		
		return finalStream;
	}
	
	/**
	 * Generates stream from the given URL
	 * @param url The URL to get the stream
	 * @return A string with the URL content
	 * @throws UtilityException
	 */
	public static String getStream(String url) throws UtilityException{
		return getStream(url, null);
	}
	
	private static String getStreamWithAuthentication(String url) throws MalformedURLException, IOException{
		logger.info("Loading stream from an authenticated URL");
		
		int dobleDot = url.lastIndexOf(":");
		int begin = "http://".length();
		int at = url.indexOf("@");
		
		String username = url.substring(begin, dobleDot);
		String password = url.substring(dobleDot + 1, at);
		
		Authenticator auth = new HttpBasicAuthenticator(username, password);
		Authenticator.setDefault(auth);
		
		URL authUrl = new URL(url);
		
		return getStringFromStream(authUrl.openStream());
		
	}
	
	private static String getStringFromStream(InputStream is) throws IOException{
		StringBuilder siteString = new StringBuilder();
		BufferedReader br = null;
			
		br = new BufferedReader( new InputStreamReader(is));
		
		String line = "";
		
		while( (line = br.readLine()) != null ){
			siteString.append( line );
		}
		
		return siteString.toString();
	}
	
	/**
	 * Return the host from an URL
	 * @param url The URL
	 * @return The host
	 * @throws UtilityException
	 */
	public static String getHost(String url) throws UtilityException{
		URL urlSite = null;
		try {
			urlSite = new URL(url);
		} catch (MalformedURLException e) {
			throw new UtilityException(e);
		}
		
		return urlSite.getHost();
	}
	
	/**
	 * Returns the query part from the URL
	 * @param url The URL
	 * @return The query part
	 * @throws UtilityException
	 */
	public static String getQuery(String url) throws UtilityException{
		URL urlSite = null;
		try {
			urlSite = new URL(url);
		} catch (MalformedURLException e) {
			throw new UtilityException(e);
		}
		
		return urlSite.getQuery();
	}
}
